/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package simplemetrosystem.control.Calculation;

import simplemetrosystem.control.ConfigureManager;
import simplemetrosystem.model.Element.MetroEdge;
import simplemetrosystem.model.Element.MetroLine;

/**
 *
 * @author Eric Qian
 */
public class CostCalculation {

    public static CostCalculation getInstance() {
        if (calculation == null) {
            ConfigureManager cm = ConfigureManager.getInstance();
            calculation = new CostCalculation(cm.getMinCost(), cm.getMaxCost(),
                    cm.getMinkm(), cm.getPerkmcost(), cm.getVirchange());
        }
        return calculation;
    }

    private CostCalculation(int minCost, int maxCost, double minKM,
            double perKMCost, int virchange) {
        this.minCost = minCost;
        this.maxCost = maxCost;
        this.minCostKM = minKM;
        this.perKMCost = perKMCost;
        this.virchange = virchange;
    }

    /**
     * 
     * @param edges
     * @param change
     * @return
     */
    public int getCost(MetroEdge[] edges, boolean change) {
        //MetroLine currentLine = edges[0].getLine();
        double distance = 0;
        int cost = 0;
        int virualChange = 0;

        for (int i = 0; i < edges.length; i++) {
            if (!edges[i].getLine().getStatus().equals(MetroLine.STATUS_FOOT)) {
                distance += edges[i].getDistance();
            } else {
                if (i - 1 > 0 && i + 1 < edges.length) {
                    if (edges[i - 1].getLine().getStatus().equals(MetroLine.STATUS_METRO) &&
                            edges[i + 1].getLine().getStatus().equals(MetroLine.STATUS_METRO)) {
                        cost += calLineCost(distance);
                        distance = 0;
                        virualChange++;
                    }
                }
            }
        }

        if (distance != 0) {
            cost += calLineCost(distance);
        }

        if (change) {
            cost -= virualChange * virchange;
        }

        return cost;
    }

    private int calLineCost(double distance) {
        if (distance < minCostKM) {
            return minCost;
        } else {
            int cost = (int) ((distance - minCostKM) * perKMCost);
            if (cost < perKMCost * (distance - minCostKM)) {
                cost++;
            }
            cost += minCost;
            return cost;
        }
    }
    private static CostCalculation calculation;
    private int minCost;
    private double minCostKM;
    private int maxCost;
    private double perKMCost;
    private int virchange;
}
